"""
存储管理器模块
统一管理多种存储后端，提供策略模式实现
"""
from typing import Dict, Any, BinaryIO, List, Optional
from enum import Enum

from flask import current_app

from app.storage.base import StorageBase
from app.storage.local import LocalStorage
from app.storage.cloud import CloudStorage
from app.utils.exceptions import StorageError


class StorageType(Enum):
    """存储类型枚举"""
    LOCAL = "local"
    CLOUD = "cloud"
    HYBRID = "hybrid"


class StorageManager:
    """
    存储管理器
    统一管理多种存储后端，支持策略切换
    """
    
    def __init__(self, app=None):
        """
        初始化存储管理器
        
        Args:
            app: Flask应用实例
        """
        self.app = app
        self.storages: Dict[str, StorageBase] = {}
        self.default_storage: Optional[StorageBase] = None
        self.current_storage_type: StorageType = StorageType.LOCAL
        
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app):
        """
        初始化存储管理器与Flask应用
        
        Args:
            app: Flask应用实例
        """
        self.app = app
        
        # 获取配置
        run_mode = app.config.get('RUN_MODE', 'local')
        storage_config = self._get_storage_config()
        
        # 根据运行模式初始化存储
        if run_mode == 'local':
            self._setup_local_storage(storage_config)
        elif run_mode == 'cloud':
            self._setup_cloud_storage(storage_config)
        else:
            self._setup_hybrid_storage(storage_config)
        
        # 设置默认存储
        self.default_storage = self.storages.get(run_mode)
        self.current_storage_type = StorageType(run_mode)
        
        app.logger.info(f"存储管理器初始化完成，当前模式: {run_mode}")
    
    def _get_storage_config(self) -> Dict[str, Any]:
        """
        获取存储配置
        
        Returns:
            dict: 存储配置
        """
        return {
            'local': {
                'base_path': self.app.config.get('UPLOAD_FOLDER', 'instance/uploads'),
                'max_file_size': self.app.config.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024),
                'allowed_extensions': self._get_allowed_extensions()
            },
            'cloud': {
                'provider': self.app.config.get('CLOUD_STORAGE_PROVIDER', 'aws_s3'),
                'bucket_name': self.app.config.get('S3_BUCKET', ''),
                'region': self.app.config.get('S3_REGION', 'us-east-1'),
                'access_key_id': self.app.config.get('AWS_ACCESS_KEY'),
                'secret_access_key': self.app.config.get('AWS_SECRET_KEY'),
                'endpoint_url': self.app.config.get('S3_ENDPOINT'),
                'max_file_size': self.app.config.get('MAX_CONTENT_LENGTH', 16 * 1024 * 1024),
                'allowed_extensions': self._get_allowed_extensions()
            }
        }
    
    def _get_allowed_extensions(self) -> List[str]:
        """
        获取允许的文件扩展名列表
        
        Returns:
            list: 允许的扩展名列表
        """
        allowed_extensions = set()
        extensions_config = self.app.config.get('ALLOWED_EXTENSIONS', {})
        
        for category, exts in extensions_config.items():
            allowed_extensions.update(exts)
        
        return list(allowed_extensions)
    
    def _setup_local_storage(self, config: Dict[str, Any]):
        """设置本地存储"""
        try:
            local_storage = LocalStorage(config['local'])
            self.storages['local'] = local_storage
            self.app.logger.info("本地存储初始化成功")
        except Exception as e:
            self.app.logger.error(f"本地存储初始化失败: {e}")
            raise StorageError(f"本地存储初始化失败: {e}")
    
    def _setup_cloud_storage(self, config: Dict[str, Any]):
        """设置云存储"""
        try:
            cloud_storage = CloudStorage(config['cloud'])
            self.storages['cloud'] = cloud_storage
            self.app.logger.info("云存储初始化成功")
        except Exception as e:
            self.app.logger.error(f"云存储初始化失败: {e}")
            # 云存储失败时回退到本地存储
            self.app.logger.warning("云存储失败，回退到本地存储")
            self._setup_local_storage(config)
            self.default_storage = self.storages['local']
            self.current_storage_type = StorageType.LOCAL
    
    def _setup_hybrid_storage(self, config: Dict[str, Any]):
        """设置混合存储"""
        self._setup_local_storage(config)
        self._setup_cloud_storage(config)
        self.app.logger.info("混合存储初始化成功")
    
    def save(self, file_data: BinaryIO, filename: str, 
             folder: str = '', metadata: Dict[str, Any] = None,
             storage_type: StorageType = None) -> Dict[str, Any]:
        """
        保存文件
        
        Args:
            file_data: 文件数据
            filename: 文件名
            folder: 文件夹
            metadata: 元数据
            storage_type: 存储类型
            
        Returns:
            dict: 文件信息
        """
        storage = self._get_storage(storage_type)
        
        try:
            result = storage.save(file_data, filename, folder, metadata)
            
            # 如果是混合模式，同时在本地备份
            if (self.current_storage_type == StorageType.HYBRID and 
                storage_type != StorageType.LOCAL):
                try:
                    file_data.seek(0)  # 重置文件指针
                    local_storage = self.storages['local']
                    local_storage.save(file_data, filename, folder, metadata)
                except Exception as e:
                    self.app.logger.warning(f"混合存储备份失败: {e}")
            
            return result
            
        except Exception as e:
            self.app.logger.error(f"文件保存失败: {e}")
            raise StorageError(f"文件保存失败: {e}")
    
    def get(self, file_id: str, storage_type: StorageType = None) -> BinaryIO:
        """
        获取文件
        
        Args:
            file_id: 文件ID
            storage_type: 存储类型
            
        Returns:
            BinaryIO: 文件数据
        """
        storage = self._get_storage(storage_type)
        
        try:
            return storage.get(file_id)
        except StorageError:
            # 如果指定存储失败，尝试其他存储（混合模式）
            if self.current_storage_type == StorageType.HYBRID:
                for other_storage in self.storages.values():
                    if other_storage != storage:
                        try:
                            return other_storage.get(file_id)
                        except StorageError:
                            continue
            
            raise
    
    def delete(self, file_id: str, storage_type: StorageType = None) -> bool:
        """
        删除文件
        
        Args:
            file_id: 文件ID
            storage_type: 存储类型
            
        Returns:
            bool: 是否删除成功
        """
        storage = self._get_storage(storage_type)
        
        try:
            success = storage.delete(file_id)
            
            # 如果是混合模式，同时删除其他存储中的副本
            if success and self.current_storage_type == StorageType.HYBRID:
                for other_storage in self.storages.values():
                    if other_storage != storage:
                        try:
                            other_storage.delete(file_id)
                        except StorageError:
                            continue  # 忽略删除失败
            
            return success
            
        except Exception as e:
            self.app.logger.error(f"文件删除失败: {e}")
            raise StorageError(f"文件删除失败: {e}")
    
    def exists(self, file_id: str, storage_type: StorageType = None) -> bool:
        """
        检查文件是否存在
        
        Args:
            file_id: 文件ID
            storage_type: 存储类型
            
        Returns:
            bool: 文件是否存在
        """
        storage = self._get_storage(storage_type)
        return storage.exists(file_id)
    
    def get_url(self, file_id: str, expires_in: int = 3600, 
                storage_type: StorageType = None) -> str:
        """
        获取文件URL
        
        Args:
            file_id: 文件ID
            expires_in: 过期时间
            storage_type: 存储类型
            
        Returns:
            str: 文件URL
        """
        storage = self._get_storage(storage_type)
        return storage.get_url(file_id, expires_in)
    
    def get_metadata(self, file_id: str, storage_type: StorageType = None) -> Dict[str, Any]:
        """
        获取文件元数据
        
        Args:
            file_id: 文件ID
            storage_type: 存储类型
            
        Returns:
            dict: 文件元数据
        """
        storage = self._get_storage(storage_type)
        return storage.get_metadata(file_id)
    
    def list_files(self, prefix: str = '', limit: int = 100,
                   storage_type: StorageType = None) -> List[Dict[str, Any]]:
        """
        列出文件
        
        Args:
            prefix: 前缀
            limit: 数量限制
            storage_type: 存储类型
            
        Returns:
            list: 文件列表
        """
        storage = self._get_storage(storage_type)
        return storage.list_files(prefix, limit)
    
    def _get_storage(self, storage_type: StorageType = None) -> StorageBase:
        """
        获取存储实例
        
        Args:
            storage_type: 存储类型
            
        Returns:
            StorageBase: 存储实例
        """
        if storage_type is None:
            return self.default_storage
        
        storage_key = storage_type.value
        storage = self.storages.get(storage_key)
        
        if storage is None:
            raise StorageError(f"存储类型未配置: {storage_key}")
        
        return storage
    
    def switch_storage(self, storage_type: StorageType) -> bool:
        """
        切换存储类型
        
        Args:
            storage_type: 新的存储类型
            
        Returns:
            bool: 是否切换成功
        """
        try:
            storage = self._get_storage(storage_type)
            self.default_storage = storage
            self.current_storage_type = storage_type
            
            self.app.logger.info(f"存储类型已切换到: {storage_type.value}")
            return True
            
        except StorageError as e:
            self.app.logger.error(f"存储切换失败: {e}")
            return False
    
    def get_storage_info(self) -> Dict[str, Any]:
        """
        获取存储信息
        
        Returns:
            dict: 存储信息
        """
        info = {
            'current_storage': self.current_storage_type.value,
            'available_storages': list(self.storages.keys()),
            'storages': {}
        }
        
        for name, storage in self.storages.items():
            try:
                if hasattr(storage, 'get_disk_usage'):
                    # 本地存储
                    storage_info = storage.get_disk_usage()
                elif hasattr(storage, 'get_bucket_info'):
                    # 云存储
                    storage_info = storage.get_bucket_info()
                else:
                    storage_info = {'type': type(storage).__name__}
                
                info['storages'][name] = storage_info
                
            except Exception as e:
                info['storages'][name] = {'error': str(e)}
        
        return info
    
    def migrate_file(self, source_file_id: str, target_storage: StorageType,
                     source_storage: StorageType = None) -> Dict[str, Any]:
        """
        迁移文件到其他存储
        
        Args:
            source_file_id: 源文件ID
            target_storage: 目标存储类型
            source_storage: 源存储类型
            
        Returns:
            dict: 迁移结果
        """
        try:
            # 获取源文件
            source_storage_instance = self._get_storage(source_storage)
            file_data = source_storage_instance.get(source_file_id)
            
            # 获取文件元数据
            metadata = source_storage_instance.get_metadata(source_file_id)
            
            # 保存到目标存储
            target_storage_instance = self._get_storage(target_storage)
            result = target_storage_instance.save(
                file_data, 
                metadata.get('original_filename', source_file_id),
                metadata=metadata.get('metadata', {})
            )
            
            # 关闭文件流
            if hasattr(file_data, 'close'):
                file_data.close()
            
            self.app.logger.info(f"文件迁移成功: {source_file_id} -> {target_storage.value}")
            
            return {
                'success': True,
                'source_file_id': source_file_id,
                'target_file_id': result['file_id'],
                'source_storage': source_storage_instance.__class__.__name__,
                'target_storage': target_storage_instance.__class__.__name__,
                'result': result
            }
            
        except Exception as e:
            self.app.logger.error(f"文件迁移失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'source_file_id': source_file_id,
                'target_storage': target_storage.value
            }
    
    def cleanup(self):
        """清理资源"""
        for storage in self.storages.values():
            if hasattr(storage, 'cleanup_temp_files'):
                storage.cleanup_temp_files()


# 全局存储管理器实例
storage_manager = StorageManager()

def init_storage_manager(app):
    """
    初始化全局存储管理器
    
    Args:
        app: Flask应用实例
    """
    storage_manager.init_app(app)
    return storage_manager